import serial
import time
import os
import sys
import random
import re
import datetime
import math
import subprocess
import _thread

#定义常量
UART_PORT     = "COM23"
DEBUG_PORT    = "COM4"
AT_PORT       = "COM39"
MODEM_PORT    = "COM28"
BAUDRATE      = 115200
DevicesID     = '580bcc85'

#定义变量
uart_serial     = None
debug_serial    = None
at_serial       = None
modem_serial    = None

#记录运行次数
runTimes        = 0
#记录解PIN成功时间戳
unlockPINTimestamp = 0
#记录找网成功耗时
foundNetWorkTime  = 0
#开机平均时间
averagePowerTime  = 0
#找网平均时间
averageFindNetWorkTime  = 0
#是否需要登录
needCheckLockStat  = 1

#log文件
AT_LOG    	  = ""
DEBUG_LOG 	  = ""
ADB_LOG       = ""
STATISTIC_LOG = ""

PowerOnOffTypes = [
	"Reboot powerOnOff",
	"VBAT powerOnOff",
	"VBAT Random powerOnOff",
	"Reboot+VBAT random powerOnOff",
	"CFUN1_1 powerOnOff",
	"CFUN1_1+VBAT random powerOnOff",
	"halt_p+VBAT powerOnOff",
	"VBAT Random powerOnOff + QMESA"
]

powerOnOffType = 0

#发送at指令
def at_write(command, timeout, at_port_opened, at_result,RDY=0,CPIN=0):
	at_command = command.encode("UTF-8")
	at_port_opened.write(at_command)

#读取at口返回
def at_read(at_port_opened):
	rec_str = ''
	while (True):
		time.sleep(1)
		lenth = at_port_opened.inWaiting()
		if lenth>0 :
			rec_str = at_port_opened.read(size=lenth)
			try:
				return re.sub( '\\x1b.*?m',"", rec_str.decode("UTF-8"),0, re.I)
			except:
				return ""
		else:
			break
	return rec_str

#检查端口连接状态
def check_port_status():
	global uart_serial
	global debug_serial

	try:
		debug_serial = serial.Serial(DEBUG_PORT,BAUDRATE)
	except:
		print("[" + str(datetime.datetime.now()) + "]debug口连接失败，请检查端口")
		sys.exit()
	# try:
		# uart_serial = serial.Serial(UART_PORT,BAUDRATE)
	# except:
		# print("[" + str(datetime.datetime.now()) + "]uart口连接失败，请检查端口")
		# sys.exit()

#检查AT口通信状态
def check_AT_singnal():
	global at_serial

	if at_serial == None:
		try:
			at_serial = serial.Serial(AT_PORT,BAUDRATE)
		except:
			print("[" + str(datetime.datetime.now()) + "]at口连接失败，请检查端口")
			sys.exit()

def loginDevice():

	#确认登录失败的条件，或者，不可能失败
	while True:
		print("[" + str(datetime.datetime.now()) + "]等待登录... ... ")
		time.sleep(3)
		at_write("\r\n",3,debug_serial,"OK")
		result = at_read(debug_serial)

		with open(DEBUG_LOG, 'a') as file_object:
			file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))

		if "login:" in result:
			at_write("root\r\n",3,debug_serial,"OK")
			print("[" + str(datetime.datetime.now()) + "]账号输入成功")
			time.sleep(2)
			at_write("fmOlFugB5vYQqM2ugwE-EJAFaBkPiU0DBLxwW1adToai8qKA5NXYKAMotNHNn5XMjH4pzieLzh9e-JsLfTEo1zgBozMiSc-x3CnO8luM0aSNFun1NgbgBOKkDf-S1tfC\r\n",3,debug_serial,"OK")
			print("[" + str(datetime.datetime.now()) + "]密码输入成功")
		elif "~ #" in result:
			print("[" + str(datetime.datetime.now()) + "]登录成功")
			at_write("echo 2 >/proc/sys/kernel/printk\r\n",3,debug_serial,"OK")
			break
		else:

			continue 

def checkdebuglog():

	#确认登录失败的条件，或者，不可能失败
	while True:
		# print("[" + str(datetime.datetime.now()) + "]等待登录... ... ")
		# time.sleep(3)
		# at_write("\r\n",3,debug_serial,"OK")
		result = at_read(debug_serial)

		with open(DEBUG_LOG, 'a') as file_object:
			file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))

		if "is_dms_qmi_init is 1 while handle modem online, need to uninit dms then reinit again" in result:
			# at_write("root\r\n",3,debug_serial,"OK")
			print("[" + str(datetime.datetime.now()) + "]问题复现")
			# os.popen('adb -s {} pull /tmp/logcat.txt'.format(DevicesID)).read()
			sys.exit()
			# time.sleep(2)
			# at_write("oelinux123\r\n",3,debug_serial,"OK")
			# print("[" + str(datetime.datetime.now()) + "]密码输入成功")
		elif "is_quec_qmi_init is 1 while handle modem online, need to uninit quec then reinit again" in result:
			print("[" + str(datetime.datetime.now()) + "]问题复现")
			# at_write("echo 2 >/proc/sys/kernel/printk\r\n",3,debug_serial,"OK")
			# os.popen('adb -s {} pull /tmp/logcat.txt'.format(DevicesID)).read()
			sys.exit()
		elif "modem online" in result or 'need to uninit quec then reinit again' in result:
			print("[" + str(datetime.datetime.now()) + "]问题复现")
			# os.popen('adb -s {} pull /tmp/logcat.txt'.format(DevicesID)).read()
			sys.exit()
		else:
			continue 

def getPowerOnOffType():
	global powerOnOffType

	for i in range(len(PowerOnOffTypes)):
		print("{}、{}".format(i,PowerOnOffTypes[i]))
	powerOnOffType = input("please select powerOnOffType : ")
	while True:
		try:
			powerOnOffType = int(powerOnOffType)
		except:
			powerOnOffType = input("invalid value ,please reinput:")
			continue

		if 0 > int(powerOnOffType) or len(PowerOnOffTypes) <= powerOnOffType:
			powerOnOffType = input("invalid value ,please reinput:")
			continue
		else:
			break

def reboot():
	at_write("sys_reboot\r\n",3,debug_serial,"OK")
	result = at_read(debug_serial)
	with open(DEBUG_LOG, 'a+') as file_object:
		file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))
	print("[" + str(datetime.datetime.now()) + "]下发reboot重启模块")
	# for i in range(70):
	# 	result = at_read(debug_serial)
	# 	with open(DEBUG_LOG, 'a') as file_object:
	# 		file_object.write(result)
	# 	if "login:" in result:
	# 		break
def check_cefs():
	print('This step is AT+QPRTPARA=4')
	at_write("AT+QPRTPARA=4\r\n",3,at_serial,"OK")
	time.sleep(5)
	result = at_read(at_serial)
	with open(AT_LOG, 'a+') as file_object:
		file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))
def cfun1_1():
	at_write("at+cfun=1,1\r\n",3,at_serial,"OK")
	time.sleep(5)
def set_dump():
	print('This step is AT+qtest=\"dump\",1')
	at_write("AT+qtest=\"dump\",1\r\n",3,at_serial,"RDY")
	for i in range(10):
		result = at_read(at_serial)
		print(result)
		with open(AT_LOG, 'a+') as file_object:
			file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))
		if 'RDY' in result:
			break
def halt_p():
	at_write("halt -p\r\n",3,debug_serial,"OK")
	at_read(debug_serial)
	time.sleep(60)

def powerOff():
	uart_serial.dtr = True
	print("[" + str(datetime.datetime.now()) + "]power off")

def powerOn():
	uart_serial.dtr = False
	print("[" + str(datetime.datetime.now()) + "]power on")

def QMESArun():
	at_write("cd /data\r\n",3,debug_serial,"OK")
	print("QMESA run {}\r\n".format(time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime())))
	at_write("./QMESA_32.32\r\n",3,debug_serial,"OK")
	time.sleep(300)
	debug_serial.write(chr(0x03).encode())
	print("QMESA stop {}\r\n".format(time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime())))
	result = at_read(debug_serial)
	with open(DEBUG_LOG, 'a+') as file_object:
		file_object.write(result)

def powerOnOff():
	global runTimes

	if 0 == powerOnOffType:
		reboot()

	elif 1 == powerOnOffType:
		powerOff()
		time.sleep(2)
		powerOn()

	elif 2 == powerOnOffType:
		powerOff()
		time.sleep(2)
		i = 0
		while i<5:
			powerOn()
			time.sleep(float("%.3f"%random.uniform(7,10)))
			powerOff()
			time.sleep(2)
			i += 1
		powerOn()

	elif 3 == powerOnOffType:
		global randomValue
		reboot()
		randomValue = "%.3f" % random.uniform(1, 30)
		print("[" + str(datetime.datetime.now()) + "]开机过程中随机断电,当前随机值为：{}S\r\n".format(randomValue))
		# result = at_read(debug_serial)
		print("######################")
		for i in range(math.floor(float(randomValue))):
			time.sleep(1)
			result = at_read(debug_serial)
			with open(DEBUG_LOG, 'a+') as file_object:
				# file_object.write("##########################当前随机断电时间为{}S##############".format(i+1))
				file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))
		time.sleep(float(randomValue) - math.floor(float(randomValue)))
		result = at_read(debug_serial)
		with open(DEBUG_LOG, 'a+') as file_object:
			file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))
		# with open(DEBUG_LOG, 'a+') as file_object:
			file_object.write("##########################随机断电时间为{}S,结束，开始下电##############".format(randomValue))
		powerOff()
		time.sleep(2)
		# result = at_read(debug_serial)
		# with open(DEBUG_LOG, 'a+') as file_object:
			# file_object.write(result)
		with open(DEBUG_LOG, 'a+') as file_object:
			file_object.write("[" + str(datetime.datetime.now()) + "]\n##########################开始上电##############".format(randomValue))
		powerOn()
		result = at_read(debug_serial)
		with open(DEBUG_LOG, 'a+') as file_object:
			file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(result))
		# loginDevice()

	elif 4 == powerOnOffType:
		cfun1_1()

	elif 5 == powerOnOffType:
		cfun1_1()
		time.sleep(float("%.3f"%random.uniform(1,30)))
		powerOff()
		time.sleep(2)
		powerOn()

	elif 6 == powerOnOffType:
		halt_p()
		powerOn()

	elif 7 == powerOnOffType:
		QMESArun()
		powerOff()
		time.sleep(2)
		powerOn()
		time.sleep(float("%.3f"%random.uniform(1,30)))
		powerOff()
		time.sleep(2)
		powerOn()


def creatLogFile():
	global AT_LOG
	global DEBUG_LOG
	global ADB_LOG
	global STATISTIC_LOG
	AT_LOG = "AT_LOG_{}.log".format(time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime()))
	# DEBUG_LOG = "DEBUG_LOG_{}.log".format(time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime()))
	ADB_LOG = "ADB_LOG_{}.log".format(time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime()))
	STATISTIC_LOG = "STATISTIC_LOG_{}.log".format(time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime()))
	# with open(STATISTIC_LOG, 'a+') as file_object:
		# file_object.write("time{0}runTimes{0}powerOnUsedTime{0}averagePowerTime{0}findNetWordTime{0}averageFindNetWorkTime\r\n".format((" "*10)))

def writeRuntimesToLog():
	global runTimes
	# with open(DEBUG_LOG, 'a+') as file_object:
		# file_object.write("[" + str(datetime.datetime.now()) + "]\n\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes+1,">"*20))
	with open(ADB_LOG, 'a+') as file_object:
		file_object.write("[" + str(datetime.datetime.now()) + "]\n\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes+1,">"*20))
	# with open(AT_LOG, 'a+') as file_object:
		# file_object.write("[" + str(datetime.datetime.now()) + "]\n\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes+1,">"*20))
	runTimes =runTimes + 1

def getNetWorkInfo():
	global foundNetWorkTime

	findNetWorkCnt = 0
	foundNetWorkStamp = 0
	while True:
		findNetWorkCnt += 1
		at_write("AT+CREG?;+CGREG?;+CEREG?;+COPS?;+QCSQ;+QNWINFO\r\n",3,at_serial,"OK")
		result = at_read(at_serial)
		#找网结果写入log
		with open(AT_LOG, 'a+') as file_object:
			file_object.write("[" + str(datetime.datetime.now()) + "]当前找网结果： {}\r\n".format(result))

		# 这里判断是否找到4G
		if ("+CGREG: 0,1" in result) and ("+CEREG: 0,1" in result) and (("+CREG: 0,3" in result) or ("+CREG: 0,1" in result)) and ("LTE" in result):
			#找到4G
			foundNetWorkStamp = int(time.time())
			with open(AT_LOG, 'a+') as file_object:
				file_object.write("[" + str(datetime.datetime.now()) + "]找网完成时间： {}\r\n".format(time.strftime("%Y--%m--%d %H:%M:%S", time.localtime(foundNetWorkStamp))))

			at_write("AT+QENG=\"SERVINGCELL\"\r\n",3,at_serial,"OK")
			result = at_read(at_serial)
			#找网结果写入log
			with open(AT_LOG, 'a+') as file_object:
				file_object.write("[" + str(datetime.datetime.now()) + "]当前servingcell： {}\r\n".format(result))
			foundNetWorkTime = foundNetWorkStamp-unlockPINTimestamp
			break
		# 这里判断是否找到5G
		elif ("+CGREG: 0,1" in result) and ("+CEREG: 0,1" in result) and (("+CREG: 0,0" in result) or ("+CREG: 0,1" in result)) and ("NR5G" in result):
			#找到4G
			foundNetWorkStamp = int(time.time())
			with open(AT_LOG, 'a+') as file_object:
				file_object.write("[" + str(datetime.datetime.now()) + "]找网完成时间： {}\r\n".format(time.strftime("%Y--%m--%d %H:%M:%S", time.localtime(foundNetWorkStamp))))

			at_write("AT+QENG=\"SERVINGCELL\"\r\n",3,at_serial,"OK")
			result = at_read(at_serial)
			#找网结果写入log
			with open(AT_LOG, 'a+') as file_object:
				file_object.write("[" + str(datetime.datetime.now()) + "]当前servingcell： {}\r\n".format(result))
			foundNetWorkTime = foundNetWorkStamp-unlockPINTimestamp
			break

		if findNetWorkCnt == 20:
			print("[" + str(datetime.datetime.now()) + "]20S仍未找到4G/5G，重启")
			foundNetWorkStamp = int(time.time())
			with open(AT_LOG, 'a+') as file_object:
				file_object.write("[" + str(datetime.datetime.now()) + "]找网失败： {}\r\n".format(time.strftime("%Y--%m--%d %H:%M:%S", time.localtime(foundNetWorkStamp))))
			foundNetWorkTime = 9999
			break		

def PINLock():
	at_write("AT+Clck=\"sc\",1,\"1234\"\r\n",3,at_serial,"OK")
	result = at_read(at_serial)
	with open(AT_LOG, 'a+') as file_object:
		file_object.write("[" + str(datetime.datetime.now()) + "]锁PIN： {}\r\n".format(result))
	#将结果写进log
	if "OK" not in result:
		print("[" + str(datetime.datetime.now()) + "]锁PIN失败，退出")
		sys.exit()
def IntoAdbShell(adbID):
	process = subprocess.Popen("adb -s {} shell ".format(adbID), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
								   stderr=subprocess.PIPE, encoding="utf-8")
	return process

def AdbShellCommand(process, cmd, excptRes, timeout):
	info = ''
	process.stdin.write(cmd)
	process.stdin.flush()
	while True:
		info_tmp = process.stdout.readline(1024)
		info = '{}{}'.format(info, info_tmp).replace("\n\n","\n")
		if excptRes is None:
			return info
		if excptRes in info:
			print('rev: {}.'.format(info))
			# print('excptRes is in rev.')
			with open(ADB_LOG, 'a+') as file_object:
				file_object.write("[" + str(datetime.datetime.now()) + "] " + info)
			return info
		else:
			if not info:
				break
		
def ExitAdbShell(process):
	process.stdin.write("exit\r\n")
	process.stdin.flush()
def randomPowerOff():
	global randomValue
	randomValue = "%.3f" % random.uniform(1, 8)
	print("[" + str(datetime.datetime.now()) + "]升级过程中随机断电,当前随机值为：{}S\r\n".format(randomValue))
	time.sleep(float(randomValue))
	powerOff()


def PINUnlock():
	global unlockPINTimestamp

	at_write("AT+Clck=\"sc\",0,\"1234\"\r\n",3,at_serial,"OK")
	result = at_read(at_serial)
	with open(AT_LOG, 'a+') as file_object:
		file_object.write("[" + str(datetime.datetime.now()) + "]解PIN： {}\r\n".format(result))
	#将结果写进log
	if "OK" not in result:
		print("[" + str(datetime.datetime.now()) + "]解PIN失败，退出")
		sys.exit()
	#解PIN
	unlockPINTimestamp = int(time.time())
	with open(AT_LOG, 'a+') as file_object:
		file_object.write("[" + str(datetime.datetime.now()) + "]解PIN完成时间： {}\r\n".format(time.strftime("%Y--%m--%d %H:%M:%S", time.localtime(unlockPINTimestamp))))

def checkLockStat():
	at_write("AT+Clck=\"sc\",2\r\n",3,at_serial,"OK")
	result = at_read(at_serial)
	if "1" in result:
		print("[" + str(datetime.datetime.now()) + "]当前已锁PIN，接下来直接重启，重启后解PIN找网")
		return "restart"
	elif "0" in result:
		print("[" + str(datetime.datetime.now()) + "]当前已解PIN，接下来锁PIN重启，重启后解PIN找网")
		return "lock_restart"
	else:
		print("[" + str(datetime.datetime.now()) + "]获取PIN状态异常，查询状态返回值为：{}，退出".format(result))
		sys.exit()

def creatTestFile():
	at_write("touch /data/test.txt\r\nsync\r\n",3,debug_serial,"OK")

def checkTestFileExist():
	at_write("ls /data\r\n",3,debug_serial,"OK")
	result = at_read(debug_serial)
	if "test.txt" not in result:
		print("[" + str(datetime.datetime.now()) + "]data下test.txt文件丢失，退出")
		sys.exit()

def getPowerOnTime():
	global averagePowerTime
	global averageFindNetWorkTime
	at_write("systemd-analyze plot > /data/systemboot.svg\r\n",3,debug_serial,"OK")
	time.sleep(5)
	at_read(debug_serial)
	os.popen("adb pull /data/systemboot.svg ./systemboot.svg")
	time.sleep(5)
	with open('systemboot.svg') as f:
		for i in f:
			if "Startup" in i:
				powerOnTime = i.split("in ")[1].split("\n")[0]
				averagePowerTime = float("%.2f"%((averagePowerTime*(runTimes-2)+float(powerOnTime.split("= ")[1].split("s")[0]))/(runTimes-1)))
				if foundNetWorkTime != 9999:
					averageFindNetWorkTime = float("%.2f"%((averageFindNetWorkTime*(runTimes-2)+foundNetWorkTime)/(runTimes-1)))
					print(powerOnTime,float(powerOnTime.split("= ")[1].split("s")[0]),runTimes,averageFindNetWorkTime,foundNetWorkTime)
				with open(STATISTIC_LOG, 'a+') as file_object:
					file_object.write("{}{}{}{}{}{}{}{}{}{}{}\r\n".format(time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime())," "*10,(runTimes-1)," "*10,powerOnTime," "*10,averagePowerTime," "*10,foundNetWorkTime," "*10,averageFindNetWorkTime))
	#os.popen("rm systemboot.svg")

def checkOemappMount():
	at_write("df -h\r\n",3,debug_serial,"OK")
	result = ""
	while True:
		tmpResult = at_read(debug_serial)
		if tmpResult != "":
			result = "{}{}".format(result,tmpResult)
		else:
			if "oemapp" in result:
				print("[" + str(datetime.datetime.now()) + "]oemapp mount success")
				break
			else:
				print("[" + str(datetime.datetime.now()) + "]oemapp mount failed")
				break

# getPowerOnOffType()
#连接端口
# check_port_status()
# check_AT_singnal()
creatLogFile()
# try:
	# _thread.start_new_thread( checkdebuglog,())
# except:
	# print ("Error: 无法check debug_serial,请检查端口.")

# process1 = IntoAdbShell()
# process1 = IntoAdbShell(DevicesID)
process2 = IntoAdbShell(DevicesID)
AdbShellCommand(process2, 'ql_sdk_api_test\r\n', 'exit', 1)
# print("11111111111111")
time.sleep(1)
AdbShellCommand(process2, '7\r\n', 'exit', 1)
# set_dump()
# time.sleep(70)
# powerOn()
while True:
	print(f'--------------> runTimes is {runTimes+1}')
	writeRuntimesToLog()
	# checkdebuglog()
	# loginDevice()
	# process1 = IntoAdbShell(DevicesID)
	# process2 = IntoAdbShell(DevicesID)
	# process3 = IntoAdbShell(DevicesID)
	# AdbShellCommand(process2, 'ql_sdk_api_test\r\n', 'exit', 1)
	print("11111111111111")
	time.sleep(1)
	# AdbShellCommand(process2, '7\r\n', 'exit', 1)
	AdbShellCommand(process2, '0\r\n', 'dm init ok', 1)
	time.sleep(1)
	AdbShellCommand(process2, '9\r\n', '860279050002095', 1)
	# AdbShellCommand(process2, '26\r\n', 'ret = 0', 1)
	# AdbShellCommand(process1, 'echo 1 > /sys/devices/platform/831000.serial/console_enable\r\n', None, 1)
	# time.sleep(1)
	# AdbShellCommand(process1, 'systemctl stop diag_service\r\n', None, 1)
	# time.sleep(1)
	# AdbShellCommand(process3, 'echo high > /sys/bus/platform/devices/a600000.ssusb/speed\r\n', None, 1)
	time.sleep(5)
	check_AT_singnal()
	check_cefs()
	time.sleep(5)
	set_dump()
	at_serial = None
	# print('Execute API is ql_dm_set_modem_restart, next sleep 30S')
	# res = ''
	# for i in range(30):
		# tmp = at_read(debug_serial)
		# res = res + tmp
		# print(f'第{i+1}/{runTimes+1}次检查debug口上报：-------{res}------')
		# with open(DEBUG_LOG, 'a+') as file_object:
			# file_object.write("[" + str(datetime.datetime.now()) + "]\n" + str(res))
		# if "current modem status is ONLINE" in res:
			# print("ONLINE事件上报正常, Execute modem reset, next sleep 70S")
			# break
		# elif i == 29:
			# print("问题复现")
			# sys.exit()
	time.sleep(70)
	# time.sleep(30)
	# checkOemappMount()
	# checkOemappMount()
	# check_AT_singnal()
	#初始化
	# if needCheckLockStat == 1:
		# creatTestFile()
		# pinStat = checkLockStat()
		# needCheckLockStat = 0
		# if pinStat == "restart":
			# reboot()
			# 重启
		# elif pinStat == "lock_restart":
			# PINLock()
			# reboot()
			# 锁PIN后重启
		# continue

	#检查usrdata路径下test.txt文件是否存在
	# checkTestFileExist()

	#保证在这一步已经是锁PIN开机状态
	# PINUnlock()
	# getNetWorkInfo()
	# getPowerOnTime()
	# PINLock()
	# powerOnOff()
